package core;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.ArrayDeque;
import java.util.Queue;

public class MyChannel {

    private final SocketChannel channel;

    private final EventLoop eventLoop;

    private final Queue<ByteBuffer> writeQueue;

    private final PipeLine pipeLine;

    private final ByteBuf readQueue;

    private int timeout;

    private int waitTime;

    private boolean isWaiting=false;

    public Protocol protocol=Protocol.HTTP;

    public MyChannel(SocketChannel channel, EventLoop eventLoop) {
        this.channel = channel;
        this.eventLoop = eventLoop;
        this.writeQueue = new ArrayDeque<>();
        this.readQueue = new ByteBuf();
        this.pipeLine = new PipeLine(this,eventLoop);
    }

    public MyChannel setTimeout(int timeout){
        this.timeout=timeout;
        return this;
    }

    public MyChannel resetWaitTime(){
        this.waitTime=0;
        this.isWaiting=false;
        return this;
    }

    public MyChannel checkTimeOut(int wait){

        if (!this.isWaiting) {
            // 读写操作中，跳过超时校验
            return this;
        }

        if (waitTime>=timeout) {
            //超时退出
            this.close();
        }
        else {
           waitTime += wait;
        }
        return this;
    }

    public MyChannel doRead(SelectionKey key){
        try {
                ByteBuffer buffer=ByteBuffer.allocate(1024);
                int byteRead=channel.read(buffer);
                /*
                    read返回0有3种情况，一是某一时刻socketChannel中当前（注意是当前）没有数据可以读，这时会返回0
                    其次是bytebuffer的position等于limit了，即bytebuffer的remaining等于0，这个时候也会返回0
                    最后一种情况就是客户端的数据发送完毕了，这个时候客户端想获取服务端的反馈调用了接收函数，若服务端继续read，这个时候就会返回0
                    read返回-1说明客户端的数据发送完毕，并且主动的close socket。
                */
                if (byteRead ==-1||byteRead ==0&&buffer.hasRemaining()){
                    System.out.println("channel读取失败,IO流已结束");
                    channel.close();
                    return this;
                }
                resetWaitTime();
                // 转成可读状态
                buffer.flip();
                // 消息放入pipeLine，交给头节点, 头节点开始传递
                //pipeLine.headContext.fireChannelRead(buffer); //跳过了头节点
                pipeLine.headContext.handler.channelRead(pipeLine.headContext, buffer);
        } catch (ClosedChannelException e) {
            // 通道已关闭
            System.out.println("通道已关闭"+e.getMessage());
            //key.cancel();
        }
        catch (IOException e) {
            System.out.println("读取发生异常:"+e.getMessage());
            this.close();
        }

        return this;
    }

    public MyChannel doWrite(SelectionKey key) {

        while (!writeQueue.isEmpty()){
            ByteBuffer buffer=writeQueue.poll();
            try {
                channel.write(buffer);
                buffer.clear();
            }catch (IOException e) {
                System.out.println("IO异常，回复消息失败");
                // 根据具体原因进行处理，可能是重新连接等
                // 放入队列，等待再次进入重写
                doWriteQueue(buffer);
                break;
            }
        }
        if (writeQueue.isEmpty()) {
            System.out.println("回复消息完毕！");
        }

        // 设置只读模式
        key.interestOps(SelectionKey.OP_READ);
        this.isWaiting=true;

        return this;
    }

    public MyChannel doWriteQueue(ByteBuffer msg){
        writeQueue.add(msg);
        return this;
    }

    public MyChannel markReadQueue(){
        readQueue.mark();
        return this;
    }

    public MyChannel resetReadQueue(){
        readQueue.reset();
        return this;
    }

    public boolean moveReadQueue(int index){
        return readQueue.moveReaderIndex(index);
    }

    public MyChannel doReadQueue(byte[] msg){
        readQueue.compact();
        readQueue.put(msg);
        return this;
    }

    public byte[] getReadQueue(){
        return readQueue.get(readQueue.getCanReadSize());
    }

    public MyChannel write(Object msg){
        this.pipeLine.tailContext.write(msg);
        return this;
    }

    /**
     * 从最后一个节点进行flush，写出到头节点时调用doFlush
     */
    public MyChannel flush(){
        this.pipeLine.tailContext.flush();
        return this;
    }

    /**
     * 关注写事件，才能进行真正地写出
     */
    public MyChannel doFlush(){
        // 设置只写模式
        this.channel.keyFor(eventLoop.selector).interestOps(SelectionKey.OP_WRITE);
        return this;
    }

    public boolean isOpen() {
        return channel.isOpen();
    }

    public MyChannel close(){
        try {
            if (isOpen()) channel.close();
        } catch (IOException e) {
            System.out.println("关闭通道异常"+e.getMessage());
        }
        return this;
    }

    public MyChannel addLast(Handler handler) {
        this.pipeLine.addLast(handler);
        return this;
    }

}
